﻿using System;
using zijian666.SuperConvert.Convertor.Base;
using zijian666.SuperConvert.Core;
using zijian666.SuperConvert.Extensions;
using zijian666.SuperConvert.Interface;

namespace zijian666.SuperConvert.Convertor
{
    public class EnumConvertor<T> : FromConvertor<T>,
        IFrom<string, T>,
        IFrom<IConvertible, T>
    {
        public ConvertResult<T> From(IConvertContext context, string input)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                return default;
            }
            T result;
            try
            {
                result = (T)Enum.Parse(OutputType, input, true);
            }
            catch (Exception ex)
            {
                return ex;
            }

            if (result.Equals(default(T)))
            {
                return default;
            }
            if (Enum.IsDefined(OutputType, result))
            {
                return result;
            }
            if (Attribute.IsDefined(OutputType, typeof(FlagsAttribute)))
            {
                if (result.ToString().IndexOf(',') >= 0)
                {
                    return result;
                }
            }
            return context.ConvertFail(this, input);
        }

        public ConvertResult<T> From(IConvertContext context, IConvertible input)
            => (input.GetTypeCode()) switch
            {
                TypeCode.Empty or TypeCode.DBNull or TypeCode.DateTime or TypeCode.Boolean => context.ConvertFail(this, input),
                TypeCode.Decimal or TypeCode.Char or TypeCode.Int16 or TypeCode.Int32 or TypeCode.Int64 or TypeCode.SByte or TypeCode.Double or TypeCode.Single => (T)Enum.ToObject(OutputType, input.ToInt64(null)),
                TypeCode.Byte or TypeCode.UInt16 or TypeCode.UInt32 or TypeCode.UInt64 => (T)Enum.ToObject(OutputType, input.ToUInt64(null)),
                TypeCode.String => From(context, input.ToString(null)),
                _ => context.ConvertFail(this, input),
            };
    }
}
